package de.micromata.jak.demo;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.List;
import java.util.Random;

import de.micromata.opengis.kml.v_2_2_0.AltitudeMode;
import de.micromata.opengis.kml.v_2_2_0.Boundary;
import de.micromata.opengis.kml.v_2_2_0.ColorMode;
import de.micromata.opengis.kml.v_2_2_0.Coordinate;
import de.micromata.opengis.kml.v_2_2_0.Document;
import de.micromata.opengis.kml.v_2_2_0.Folder;
import de.micromata.opengis.kml.v_2_2_0.Kml;
import de.micromata.opengis.kml.v_2_2_0.LinearRing;
import de.micromata.opengis.kml.v_2_2_0.ListItemType;
import de.micromata.opengis.kml.v_2_2_0.MultiGeometry;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
import de.micromata.opengis.kml.v_2_2_0.Polygon;
import de.micromata.opengis.kml.v_2_2_0.Style;

/**
 * This example reads the world borders from a KML file and creates two radio folder. The first folder show all
 * countries with a coloroverlay (2D) and random colors. The second folder show a polygon (3D) with random color and
 * random height for each country. To create a 3D polygon, the object structe must be traverse until the Coordinate
 * objects.
 */
public class Example2 {

  public static void main(String args[]) throws FileNotFoundException {

    int minPolyHeight = 308000;
    int maxPolyHeight = 2692000; // real max = 3000000 - 308000 = 2692000

    String path = "src/main/resources/data/worldBorders.kml";
    Kml unmarshal = Kml.unmarshal(new File(path));

    Document document = (Document) unmarshal.getFeature();
    Folder rootFolder = new Folder().withName("choose").withStyleUrl("radioFolder");
    Folder folder3D = (Folder) document.getFeature().get(0);
    // put the original folder into the rootFolder
    document.getFeature().remove(0);
    document.addToFeature(rootFolder);
    document.setName("JAK Example2");
    Folder folder2D = new Folder();
    folder2D.withName("2D borders");
    folder3D.withName("3D borders");
    rootFolder.addToFeature(folder2D);
    rootFolder.addToFeature(folder3D);
    // set radiofolder: only one folder can be activated
    Style radioStyle = new Style().withId("radioFolder");
    radioStyle.createAndSetListStyle().withListItemType(ListItemType.RADIO_FOLDER);
    document.addToStyleSelector(radioStyle);

    int folderSize = folder3D.getFeature().size();
    // loop over all countries / Placemarks
    for (int i = 0; i < folderSize; i++) {
      Placemark placemark3D = (Placemark) folder3D.getFeature().get(i);
      placemark3D.withDescription(placemark3D.getName());
      Placemark placemark2D = Utils.clonePlacemark(placemark3D);
      folder2D.addToFeature(placemark2D);
      // use random color for the polygon and a black (default color) stroke with 1 width
      Utils.setPolyStyleAndLineStyle(placemark3D, "FFFFFFFF", ColorMode.RANDOM, 1, null, ColorMode.NORMAL);
      Utils.setPolyStyleAndLineStyle(placemark2D, "FFFFFFFF", ColorMode.RANDOM, 1, null, ColorMode.NORMAL);
      MultiGeometry multigeometry3D = (MultiGeometry) placemark3D.getGeometry();
      MultiGeometry multigeometry2D = (MultiGeometry) placemark2D.getGeometry();
      Random rand = new Random(System.nanoTime());
      // use minimal polygon height to prevent the "polygon hole problem"
      double x = rand.nextInt(maxPolyHeight) + minPolyHeight;

      for (int j = 0; j < multigeometry3D.getGeometry().size(); j++) {
        Polygon polygon3D = (Polygon) multigeometry3D.getGeometry().get(j);
        Polygon polygon2D = (Polygon) multigeometry2D.getGeometry().get(j);
        polygon3D.setAltitudeMode(AltitudeMode.RELATIVE_TO_GROUND); // altitude can only be set in this mode
        polygon2D.setAltitudeMode(AltitudeMode.CLAMP_TO_GROUND);
        polygon3D.setExtrude(Boolean.TRUE); // connect to ground
        polygon2D.setTessellate(Boolean.TRUE); // follow the terrain
        Boundary outerBoundaryIs = polygon3D.getOuterBoundaryIs();
        LinearRing linearRing = outerBoundaryIs.getLinearRing();
        List<Coordinate> coordinates = linearRing.getCoordinates();
        // set the altitude of all vertices (height of the polygon)
        for (Coordinate c : coordinates) {
          c.setAltitude(x);
        }

        // check enclaves or polygons like it
        if (!polygon3D.getInnerBoundaryIs().isEmpty()) {
          for (int k = 0; k < polygon3D.getInnerBoundaryIs().size(); k++) {
            Boundary innerBoundaryIs = polygon3D.getInnerBoundaryIs().get(k);
            LinearRing linearRingInner = innerBoundaryIs.getLinearRing();
            List<Coordinate> coordinatesInner = linearRingInner.getCoordinates();
            // set the altitude of all vertices (height of the polygon)
            for (Coordinate c : coordinatesInner) {
              c.setAltitude(x);
            }
          }
        }
      }
    }
    unmarshal.marshal(new File("src/main/resources/examples/example2.kml"));
  }
}
